package ezXpns.GUI;

import java.awt.Color;
import java.awt.event.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.UUID;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.commons.lang3.tuple.Pair;

import net.miginfocom.swing.MigLayout;

import ezXpns.*;
import ezXpns.ImportCsv.ImportFileMismatch;
import ezXpns.GUI.controllers.BudgetChangeController;
import ezXpns.GUI.controllers.ProgressController;
import ezXpns.GUI.controllers.ReportController;
import ezXpns.storage.JsonStorageEngine;
import ezXpns.storage.Storage;

import java.awt.Font;
import java.awt.Dimension;

/**
 * @author A0086931X
 */

//@author A0086931X
public class GUI {
	// analysis dummy variables
	boolean incomeExist = true;
	String incomeStatus = "No Income";
	private JLabel lblUsername;

	private JFrame frmEzxpns;
	private BudgetChangePanel expensePanel;
	private BudgetChangePanel incomePanel;
	private AnalysisGUIPanel analysisPanel;

	private ProgressBar overallProgressBar;

	private Storage<BudgetChange> expenseStorage;
	private Storage<BudgetChange> incomeStorage;

	private Profile profile = new Profile();
	private Report report = new Report();

	private String formatPrefix = "<html><body leftmargin=0 topmargin=10 marginwidth=0 marginheight=11><center>";
	private String formatSuffix = "</body></html>";
	private JTabbedPane tabbedPane;
	protected JButton btnExportExpense;
	protected JButton btnImportExpense;

	private BudgetChangeController expenseController;
	private BudgetChangeController incomeController;
	private ProgressController progressController;
	private ReportController reportController;

	private String username;

	public void close() throws Exception {
		int reply = JOptionPane.showConfirmDialog(null, "Are you sure you want to close?", "Close?",
				JOptionPane.YES_NO_OPTION);
		if (reply == JOptionPane.YES_OPTION) {
			profile.save("tmp/" + username + "-profile.txt");
			closeIfNotNull(expenseStorage);
			closeIfNotNull(incomeStorage);
			System.exit(0);
		} else {

		}

	}

	public void run(String inputName) throws IOException {
		username = inputName;
		try {
			profile.load("tmp/" + username + "-profile.txt");
			lblUsername.setText(profile.getUsername());
		} catch (FileNotFoundException e) {
		}

		JsonStorageEngine<BudgetChange> expenseStorageEngine = JsonStorageEngine.open("tmp/" + username
				+ "-expense.txt", BudgetChange.class, SerializationConfig.getGson());
		JsonStorageEngine<BudgetChange> incomeStorageEngine = JsonStorageEngine.open("tmp/" + username + "-income.txt",
				BudgetChange.class, SerializationConfig.getGson());

		expenseStorage = new Storage<BudgetChange>(expenseStorageEngine, new BudgetChangeConverter());
		incomeStorage = new Storage<BudgetChange>(incomeStorageEngine, new BudgetChangeConverter());

		expenseController = new BudgetChangeController(expenseStorage, profile.getExpenseTypes());
		incomeController = new BudgetChangeController(incomeStorage, profile.getIncomeTypes());
		progressController = new ProgressController(expenseStorage, profile);
		reportController = new ReportController(expenseStorage, incomeStorage, analysisPanel);

		expensePanel.connect(expenseController);
		incomePanel.connect(incomeController);
		progressController.connect(overallProgressBar);
		analysisPanel.connect(reportController);

		frmEzxpns.setVisible(true);

		expensePanel.setNewFocus();

		frmEzxpns.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				try {
					close();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

	}

	/**
	 * Create the application.
	 */
	public GUI() {
		initialize();

	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmEzxpns = new JFrame();
		frmEzxpns.setMinimumSize(new Dimension(920, 580));

		frmEzxpns.setTitle("EzXpns (v0.2)");
		frmEzxpns.setBounds(50, 50, 920, 552);
		frmEzxpns.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

		/*
		 * Header Bar with User information, Budget Information
		 */
		frmEzxpns.getContentPane().setLayout(
				new MigLayout("", "[600px:771.00px,grow,fill]", "[10px][292.00px:420px,grow,fill]"));
		JPanel headerBar = new JPanel();
		headerBar.setBorder(null);
		frmEzxpns.getContentPane().add(headerBar, "cell 0 0,growx,aligny top");
		headerBar.setLayout(new MigLayout("", "[62.00px][21.00px][185.00,grow,fill]", "[30]"));

		ImageIcon profileImg = new ImageIcon("assets\\Optimized Icons\\user.png");
		lblUsername = new JLabel("John Wilkinson");
		lblUsername.setFont(new Font("SansSerif", Font.BOLD, 15));
		lblUsername.setIcon(profileImg);

		headerBar.add(lblUsername, "cell 0 0");

		overallProgressBar = new ProgressBar();
		overallProgressBar.setFont(new Font("Dialog", Font.BOLD, 24));
		overallProgressBar.setBackground(Color.LIGHT_GRAY);
		overallProgressBar.setStringPainted(true);

		headerBar.add(overallProgressBar, "cell 2 0,grow");

		/**
		 * Body
		 */
		JPanel mainPanel = new JPanel();
		mainPanel.setBorder(new LineBorder(new Color(0, 0, 0), 3));
		frmEzxpns.getContentPane().add(mainPanel, "cell 0 1,alignx left,growy");
		mainPanel.setLayout(new MigLayout("", "[770px,grow,fill]", "[404px,grow]"));
		tabbedPane = new JTabbedPane(JTabbedPane.LEFT);
		mainPanel.add(tabbedPane, "cell 0 0,alignx left,aligny top,grow");
		tabbedPane.setBorder(new LineBorder(new Color(0, 0, 0)));

		/**
		 * Expense Panel
		 */
		expensePanel = new BudgetChangePanel();
		tabbedPane.addTab(formatPrefix + "<img src=\"file:assets/Optimized Icons/Hover/add.png\"  />" + formatSuffix,
				null, expensePanel, "Expenses");

		/**
		 * Income Panel
		 */
		incomePanel = new BudgetChangePanel();
		tabbedPane.addTab(
				formatPrefix + "<img src=\"file:assets/Optimized Icons/Hover/income.png\"  />" + formatSuffix, null,
				incomePanel, "Income");

		/**
		 * Analysis
		 */
		analysisPanel = new AnalysisGUIPanel(report, profile);
		tabbedPane.addTab(formatPrefix + "<img src=\"file:assets/Optimized Icons/Hover/stats.png\" />" + formatSuffix,
				null, analysisPanel, "Analysis");

		/**
		 * Settings
		 */
		JPanel settingsPanel = new JPanel();
		tabbedPane.addTab(
				formatPrefix + "<img src=\"file:assets/Optimized Icons/Hover/options.png\" />" + formatSuffix, null,
				settingsPanel, "Settings");

		settingsPanel.setLayout(new MigLayout("", "[185.00][85.00,fill][85,fill][][][][grow]",
				"[45.00][][][][][][][][][][114.00][30.00,grow]"));

		JButton btnEditProfile = new JButton("Edit Profile");
		btnEditProfile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				AccountCreationGUI editProfile = new AccountCreationGUI();
				profile = editProfile.showDialog(profile);
				lblUsername.setText(profile.getUsername());
				progressController.refresh();
			}
		});
		settingsPanel.add(btnEditProfile, "cell 1 3 2 1");

		btnImportExpense = new JButton("Import Expense");
		btnImportExpense.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				importExpense();
			}
		});
		settingsPanel.add(btnImportExpense, "cell 1 4");

		btnExportExpense = new JButton("Export Expense");
		btnExportExpense.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				exportExpense();
			}
		});
		settingsPanel.add(btnExportExpense, "cell 2 4");

		JButton btnImportIncome = new JButton("Import Income");
		btnImportIncome.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) { // import CSV
				importIncome();

			}
		});
		settingsPanel.add(btnImportIncome, "cell 1 5");

		JButton btnExportIncome = new JButton("Export Income");
		btnExportIncome.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) { // export CSV
				exportIncome();
			}
		});
		settingsPanel.add(btnExportIncome, "cell 2 5");

		JButton btnHelpabout = new JButton("Help/About");
		btnHelpabout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				AboutGUI aboutGUI = new AboutGUI();
				aboutGUI.setVisible(true);
			}
		});
		settingsPanel.add(btnHelpabout, "cell 1 7 2 1");

		JButton btnClearAll = new JButton("Clear All");
		btnClearAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int reply = JOptionPane.showConfirmDialog(null,
						"Are you sure you want to clear all? (This action cannot be undone)", "Clear All?",
						JOptionPane.YES_NO_OPTION);
				if (reply == JOptionPane.YES_OPTION) {
					System.out.println("clear all");
				}
			}
		});
		settingsPanel.add(btnClearAll, "cell 6 11");

		tabbedPane.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				if (tabbedPane.getSelectedIndex() == 0) {
					expensePanel.setNewFocus();
				}
				if (tabbedPane.getSelectedIndex() == 1) {
					incomePanel.setNewFocus();
				}
				if (tabbedPane.getSelectedIndex() == 2) {
					analysisPanel.refresh();
				}
			}
		});

		// TODO Hooks
		/*KeyboardFocusManager.getCurrentKeyboardFocusManager()
		  .addKeyEventDispatcher(new KeyEventDispatcher() {
		      @Override
		      public boolean dispatchKeyEvent(KeyEvent e) {
		                if ((e.getKeyCode() == KeyEvent.VK_C) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
		                    System.out.println("woot!");
		                    return true;
		                }else return false;
		            }
		});*/
	}

	private void exportIncome() {
		JFileChooser saveFileChooser = new JFileChooser(System.getProperty("user.home"));
		saveFileChooser.setDialogTitle("Specify a .csv file to save"); // Title
																		// of
																		// Dialog
																		// box
		int returnVal = saveFileChooser.showSaveDialog(null);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File saveFile = saveFileChooser.getSelectedFile(); // the file to be
																// saved
			String savePath = saveFile.getAbsolutePath(); // path of file to be
															// exported
			// adds filetype if not specified to be .csv
			if (!savePath.toLowerCase().endsWith(".csv")) {
				savePath += ".csv";
			}
			ExportCsv.exportIncome(savePath, incomeStorage.getAllEntries()); // exports
																				// to
																				// path
		}
	}

	private void importIncome() {
		final JFileChooser fc = new JFileChooser();
		FileNameExtensionFilter filter = new FileNameExtensionFilter("CSV Files", "csv");
		fc.setDialogTitle("Import Income");
		fc.setFileFilter(filter);
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			try {
				Vector<Pair<UUID, BudgetChange>> importData = ImportCsv.importIncome(fc.getSelectedFile().toString());
				// Vector<Pair<UUID, BudgetChange>> importData =
				// ImportCsv.importIncome("exportIncome.csv");

				for (Pair<UUID, BudgetChange> entry : importData) {
					BudgetChange temp = new BudgetChange();
					temp.setName(entry.getValue().getName());
					temp.setAmount(entry.getValue().getAmount());
					temp.setType(entry.getValue().getType());
					temp.setTagsFromString(entry.getValue().getTagsAsString());
					temp.setDate(entry.getValue().getDate());

					if (incomeStorage.get(entry.getKey()) != null) {
						System.out.println(entry.getValue().getName() + " replaced");
						incomeStorage.replace(entry.getKey(), temp);
					} else {
						System.out.println(entry.getValue().getName() + " added");
						incomeStorage.addWithId(entry.getKey(), temp);
					}
				}

			} catch (ParseException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ImportFileMismatch e) {
				e.printStackTrace();
			}
		}
	}

	private void exportExpense() {
		JFileChooser saveFileChooser = new JFileChooser(System.getProperty("user.home"));
		saveFileChooser.setDialogTitle("Specify a .csv file to save"); // Title
																		// of
																		// Dialog
																		// box
		int returnVal = saveFileChooser.showSaveDialog(null);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File saveFile = saveFileChooser.getSelectedFile(); // the file to be
																// saved
			String savePath = saveFile.getAbsolutePath(); // path of file to be
															// exported
			// adds filetype if not specified to be .csv
			if (!savePath.toLowerCase().endsWith(".csv")) {
				savePath += ".csv";
			}
			ExportCsv.exportExpense(savePath, incomeStorage.getAllEntries()); // exports
																				// to
																				// path
		}
	}

	private void importExpense() {
		final JFileChooser fc = new JFileChooser();
		FileNameExtensionFilter filter = new FileNameExtensionFilter("CSV Files", "csv");
		fc.setDialogTitle("Import Income");
		fc.setFileFilter(filter);
		int returnVal = fc.showOpenDialog(null);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			try {
				Vector<Pair<UUID, BudgetChange>> importData = ImportCsv.importExpense(fc.getSelectedFile().toString());
				// Vector<Pair<UUID, BudgetChange>> importData =
				// ImportCsv.importExpense("exportExpense.csv");

				System.out.println(importData.size());
				for (Pair<UUID, BudgetChange> entry : importData) {
					BudgetChange temp = new BudgetChange();
					temp.setName(entry.getValue().getName());
					temp.setAmount(entry.getValue().getAmount());
					temp.setType(entry.getValue().getType());
					temp.setTagsFromString(entry.getValue().getTagsAsString());
					temp.setDate(entry.getValue().getDate());

					if (expenseStorage.get(entry.getKey()) != null) {
						System.out.println(entry.getValue().getName() + " replaced");
						expenseStorage.replace(entry.getKey(), temp);
					} else {
						System.out.println(entry.getValue().getName() + " added");
						expenseStorage.addWithId(entry.getKey(), temp);
					}
				}

			} catch (ParseException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ImportFileMismatch e) {
				e.printStackTrace();
			}
		}
	}

	private static void closeIfNotNull(AutoCloseable obj) throws Exception {
		if (obj != null)
			obj.close();
	}
}
